package com.jhc.drone.communication.network;


import cn.hutool.json.JSONObject;
import com.jhc.drone.communication.datagram.command.Command;
import com.jhc.drone.communication.enums.ProtocolEnum;
import com.jhc.drone.communication.enums.WsReqEnum;
import com.jhc.drone.communication.network.cache.DroneCache;
import com.jhc.drone.communication.vo.CommandVo;
import com.jhc.drone.communication.ws.WsEndpoint;
import io.netty.channel.Channel;
import io.netty.util.AttributeKey;

import java.util.Timer;
import java.util.TimerTask;

/**
 * @author lcp
 * @date 2024年12月2024/12/30 13:58
 * @describe
 */
public abstract class Gateway {
    public ProtocolEnum protocol;
    public final static String SOCKET_TYPE_IN_CHANNEL_ATTRIBUTE = "__socket_type__";
    public static final AttributeKey<Integer> SOCKET_TYPE_IN_CHANNEL_ATTRIBUTE_ATTR = AttributeKey.newInstance(SOCKET_TYPE_IN_CHANNEL_ATTRIBUTE);
    public static final int SOCKET_TYPE_UDP = 0x0001;
    public static final int SOCKET_TYPE_TCP = 0x0002;
    public static final int SOCKET_TYPE_WEBSOCKET = 0x0004;
    public static int SESSION_RECYCLER_EXPIRE = 10;
    public static int TIMER_INTERVAL = 5000;

    public abstract void init();

    public abstract void bind() throws Exception;

    public abstract void shutdown();

    Gateway() {
    }

    public static void setSocketType(Channel c, int socketType) {
        c.attr(SOCKET_TYPE_IN_CHANNEL_ATTRIBUTE_ATTR).set(socketType);
    }

    public static void removeSocketType(Channel c) {
        c.attr(SOCKET_TYPE_IN_CHANNEL_ATTRIBUTE_ATTR).set(null);
    }

    public static int getSocketType(Channel c) {
        Integer socketType = c.attr(SOCKET_TYPE_IN_CHANNEL_ATTRIBUTE_ATTR).get();
        if (socketType != null)
            return socketType;
        return -1;
    }

    public static boolean isSupportUDP(int support) {
        return (support & SOCKET_TYPE_UDP) == SOCKET_TYPE_UDP;
    }

    public static boolean isSupportTCP(int support) {
        return (support & SOCKET_TYPE_TCP) == SOCKET_TYPE_TCP;
    }

    public static boolean isSupportWebSocket(int support) {
        return (support & SOCKET_TYPE_WEBSOCKET) == SOCKET_TYPE_WEBSOCKET;
    }

    public static boolean isTCPChannel(Channel c) {
        return (c != null && getSocketType(c) == SOCKET_TYPE_TCP);
    }

    public static boolean isUDPChannel(Channel c) {
        return (c != null && getSocketType(c) == SOCKET_TYPE_UDP);
    }

    public static boolean isWebSocketChannel(Channel c) {
        return (c != null && getSocketType(c) == SOCKET_TYPE_WEBSOCKET);
    }

    public static String $(Channel c) {
        return getGatewayFlag(c);
    }

    public static String getGatewayFlag(Channel c) {
        if (Gateway.isUDPChannel(c))
            return "udp";
        else if (Gateway.isTCPChannel(c))
            return "tcp";
        else if (Gateway.isWebSocketChannel(c))
            return "websocket";
        else
            return "unknow";
    }

    public void timerTask() {
        final Timer timer = new Timer();
        timer.schedule(new TimerTask() {

            @Override
            public void run() {
                DroneCache.ON_LINE.forEach((k, v) -> {
                    JSONObject entries = new JSONObject();
                    entries.set("uavState", v ? "在线" : "离线");
                    entries.set("sn", k);
                    WsEndpoint.sendAll(entries);
                });

                DroneCache.CHANNEL_MAP.forEach((sysId, channel) -> {
                    if (!DroneCache.SERIAL_NUMBER_MAP.containsKey(channel)) {
                        CommandVo vo = new CommandVo();
                        vo.setSysId(sysId);
                        vo.setWsReqEnum(WsReqEnum.PUSH_SERIAL_NUMBER);
                        WsEndpoint.messageProcessor.sendBySysId(Command.buildCommand(vo), sysId);
                    }
                });
            }
        }, SESSION_RECYCLER_EXPIRE, TIMER_INTERVAL);
    }
}
